﻿using IconExtractor;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace ScriptBox
{
    class ExeIcon
    {
        [StructLayout(LayoutKind.Sequential)]
        public struct SHFILEINFO
        {
            public IntPtr hIcon;
            public int iIcon;
            public uint dwAttributes;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
            public string szDisplayName;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
            public string szTypeName;
        };

        [DllImport("shell32.dll")]
        public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbSizeFileInfo, uint uFlags);

        const uint SHGFI_ICON = 0x000000100; // 获取文件图标
        const uint SHGFI_LARGEICON = 0x000000000; // 获取大图标
        const uint SHGFI_SMALLICON = 0x000000001; // 获取小图标
        const uint SHGFI_USEFILEATTRIBUTES = 0x000000010; // use file attributes if path is a directory

        /// <summary>
        /// 通过SHGetFileInfo方法获取，实测大图标尺寸32，小图标尺寸16
        /// </summary>
        /// <param name="exePath"></param>
        /// <returns></returns>
        public static Icon GetIcon_With_SHGetFileInfo(string exePath)
        {
            SHFILEINFO shfi = new SHFILEINFO();
            IntPtr hImg = SHGetFileInfo(exePath, 0, ref shfi, (uint)Marshal.SizeOf(shfi), SHGFI_ICON | SHGFI_LARGEICON | SHGFI_USEFILEATTRIBUTES);
            if ((int)hImg > 0)
            {
                Icon icon = Icon.FromHandle(shfi.hIcon);
                return icon;
            }
            return null;
        }

        [DllImport("shell32.dll", CharSet = CharSet.Auto)]
        static extern int ExtractIconEx(string lpszFile, int nIconIndex, out IntPtr phiconLarge, out IntPtr phiconSmall, int nIcons);
        /// <summary>
        /// 通过ExtractIconEx方法获取，实测大图标尺寸32，小图标尺寸16
        /// </summary>
        /// <param name="exePath"></param>
        /// <returns></returns>
        public static Icon GetIcon_With_ExtractIconEx(string exePath)
        {

            IntPtr largeIconHandle, smallIconHandle;
            int iconCount = ExtractIconEx(exePath, 0, out largeIconHandle, out smallIconHandle, 1);
            if (largeIconHandle != IntPtr.Zero)
            {
                Icon icon = Icon.FromHandle(largeIconHandle);
                //Icon icon = Icon.FromHandle(smallIconHandle);
                return icon;
            }
            return null;
        }

        /// <summary>
        /// 通过Icon类自有方法获取，实测图标尺寸32
        /// </summary>
        /// <param name="exePath"></param>
        /// <returns></returns>
        public static Icon GetIcon(string exePath)
        {
            Icon icon = Icon.ExtractAssociatedIcon(exePath);
            return icon;
        }

        /// <summary>
        /// 使用第三方库IconLib，只能提取到尺寸16
        /// </summary>
        /// <param name="exePath"></param>
        /// <returns></returns>
        //public static Icon GetIcon_With_IconLib(string exePath)
        //{
        //    // 路径为需要提取图标的exe文件的路径。
        //    MultiIcon multiIcon = new MultiIcon();
        //    multiIcon.Load(exePath);

        //    // 获取exe文件的默认图标
        //    SingleIcon singleIcon = multiIcon[0];

        //    return singleIcon.Icon;
        //}

        /// <summary>
        /// 这种方法可以提取大尺寸图标，但是如果exe中不存在大尺寸，会被强行拉伸。
        /// </summary>
        /// <param name="exePath"></param>
        /// <param name="size">需要获取的图标尺寸</param>
        /// <returns>返回能找到的最大尺寸图标</returns>
        public static Icon GetIcon_With_IconExtractor(string exePath, int size)
        {
            uint _nIcons = PInvoke.PrivateExtractIcons(exePath, 0, 0, 0, null, null, 0, 0);
            if (_nIcons == 0)
            {
                return null;
            }
            IntPtr[] phicon = new IntPtr[_nIcons];
            uint[] piconid = new uint[_nIcons];
            uint nIcons = PInvoke.PrivateExtractIcons(exePath, 0, size, size, phicon, piconid, _nIcons, 0);
            if (nIcons > 0)
            {
                Icon icon = Icon.FromHandle(phicon[0]);
                return icon;
            }
            return null;
        }
        //static int index = 0;
        public static ImageSource GetIconImage(string exePath)
        {
            if (!File.Exists(exePath))
                return null;
            //先使用IconExtractor方法找
            Icon icon = GetIcon_With_IconExtractor(exePath, 96);
            if (icon == null)//如果没找到，用默认方法找
            {
                icon = GetIcon(exePath);
            }

            //test
            //var fileStream = new System.IO.FileStream($"icon-{index++}.png", System.IO.FileMode.Create);
            //icon.Save(fileStream);
            //fileStream.Close();

            ImageSource image = Imaging.CreateBitmapSourceFromHIcon(icon.Handle, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
            return image;
        }
    }
}
